package ngat.oss;

import ngat.oss.*;
import ngat.phase2.*;
import ngat.instrument.*;
import ngat.util.*;
import ngat.util.logging.*;
import ngat.net.*;

import jyd.dbms.*;
import jyd.storable.*;
import jyd.collection.*;

import java.math.*;
import java.util.*;
import java.io.*;
import java.net.*;
import java.text.*;

/**
 * Contains variables relating to the Phase II Database Transaction Server .
 * Individual environment variables may be overridden by command line arguments,
 * using the same param values as found in the 'Server.env' file preceded with a '-' 
 * e.g. -server_command_port 6777   -t_Q_buffer 50   -enable_t_Q_sweep   etc.
 */
public class ServerContext implements Logging {

    /** TRACE Logger.*/
    private static Logger logger = LogManager.getLogger("TRACE");

    // Server News.
    private static Properties news = new Properties();
    
    public static Properties getNews() { return news;} 
       
    public static String getNewsFileName() { return globalSettings.getNewsTableFile().getPath();}
   
    
    // news latest article index.
    private static int newsLatestIndex = 0;
    
    public static int getNewsLatestIndex() { return newsLatestIndex; }
    
    public static void setNewsLatestIndex(int in) { newsLatestIndex = in;}
    
    // News updated time.
    private static long newsLatestDate = 0L;
    
    public static long getNewsLatestDate() { return newsLatestDate;}
    
    public static void setNewsLatestDate(long in) { newsLatestDate = in;}
    
    /** Read in the News from file SC.getNewsFileName()*/
    public static void loadNews() throws ServerEnvException {
	BufferedInputStream in = null;
	try {
	    in = new BufferedInputStream(new FileInputStream(globalSettings.getNewsTableFile()));
	} catch (FileNotFoundException fe1) {
	    throw new ServerEnvException("Error opening news file - could not find file");
	} catch (IOException ie1) {
	    log("Error opening news file: " + globalSettings.getNewsTableFile().getPath());
	    throw new ServerEnvException("Error opening news file: " + 
					 globalSettings.getNewsTableFile().getPath());	    
	}
	
	try {
	    news.load(in);   
	} catch( IOException ie) {
	    log("Error loading news");
	    throw  new ServerEnvException();
	}
	
	try {
	    in.close(); 
	} catch( IOException ie) {
	    log("Error closing news file");
	} 
	
	try {
	    newsLatestIndex = Integer.parseInt(news.getProperty("latest.index"));
	} catch (NumberFormatException nffe){}
	
	try { 
	    newsLatestDate = Long.parseLong(news.getProperty("news."+newsLatestIndex+".date"));
	} catch (NumberFormatException nffe){}

    }
    
    
    /** Update the News file with new entries. */
    public static void saveNewsUpdate() throws ServerEnvException {
	BufferedOutputStream out = null;
	try {
	    out = new BufferedOutputStream(new FileOutputStream(globalSettings.getNewsTableFile()));
	} catch (FileNotFoundException fe1) {
	    throw new ServerEnvException("Error opening News file - could not find file");
	} catch (IOException ie1) {
	    throw new ServerEnvException("Error opening News file: " + 
					 globalSettings.getNewsTableFile().getPath());	    
	}			   
	try {
	    news.store(out, "News Articles");
	} catch( IOException ie) {
	    log("Error saving News updates");
	    throw  new ServerEnvException("Error saving News");
	}
	try {
	    out.close();
	} catch( IOException ie) {
	    log("Error closing news file");
	} 
    }
    
    /** Retrieve news articles since given index.*/
    public static Vector getNewsSince(int index) {
	if (index > newsLatestIndex) {
	    return null;
	}
	Vector list = new Vector();
	for (int i = index; i <= newsLatestIndex; i++) {
	    String ds = "news."+i+".date";
	    String ts = "news."+i+".text";
	    log("trying date:["+ds+"] text:["+ts+"]");
	    list.addElement("Index: "+i+
			    "\nDate: "+news.getProperty(ds, "unknown")+
			    "\nText: "+news.getProperty(ts, "unknown"));
	}
	return list;
    }
    
    
    /** Retrieve news articles since given Date. */
    public static Vector getNewsSince(long date) {
	if (date > newsLatestDate) {
	    return null;
	}
	Vector list = new Vector();
	int index = 0;
	for (int i = index; i <= newsLatestIndex; i++) {
	    list.addElement("Index: "+i+
			    "\nDate: "+news.getProperty("news."+i+"date", "unknown")+
			    "\nText: "+news.getProperty("news."+i+"text", "unknown"));
	}
	return list;
    } 
    
    /** Attempt to insert a new News article entry.*/
    public static void insertNewsEntry(String text) throws ServerEnvException {
	newsLatestIndex++;
	newsLatestDate = System.currentTimeMillis();
	news.setProperty("latest.index", String.valueOf(newsLatestIndex));
	news.setProperty("news."+newsLatestIndex+".date", String.valueOf(newsLatestDate));
	news.setProperty("news."+newsLatestIndex+".text", text);
	saveNewsUpdate();
    }
    
    
    // Pause (single user mode) message
    private static String serverPauseMessage = null;
    
    public static String getServerPauseMessage() { return serverPauseMessage;}
    
    public static void setServerPauseMessage(String in) {serverPauseMessage = in;}
    
    // Expected restart time after pause.
    private static long pauseRestartTime = 0L;

    public static long getPauseRestartTime() { return pauseRestartTime;}

    public static void setPauseRestartTime(long in) {pauseRestartTime = in;}
       
  
    // Routine Logging variables - for each log channel available.
    private static PrintWriter errorLogStream;   
    private static PrintWriter traceLogStream; 
    private static PrintWriter trafficLogStream;
    private static PrintWriter scheduleLogStream;
    private static PrintWriter performanceLogStream;
   
    // Server environment (context).
    private static File baseFile = null;

    public static File getBaseFile() { return baseFile;}
    
    private static GlobalSettings globalSettings = new GlobalSettings();

    public static GlobalSettings getGlobalSettings() {return globalSettings;}

    /** Load the GlobalSettings from the specified file
     * to override hard coded defaults. 
     * @param base The configuration directory.
     * @param context The context file (e.g. oss.properties).
     */
    public static void loadContext(String base, String  context)  throws ServerEnvException {
	baseFile = new File(base);
	File contextFile = new File(baseFile, context);
	try {
	    globalSettings.configure(contextFile); 
	} catch (IOException iox) {
	    throw new ServerEnvException("Error loading global-settings from file \n["+
					 contextFile.getPath()+"]\n:"+iox);
	} catch (IllegalArgumentException e) {
	    throw new ServerEnvException("Error loading global-settings from file \n["+
					 contextFile.getPath()+"]\n:"+e);
	}	
    }
    
    // Scheduling.
    private static Scheduling scheduling = new Scheduling();

    public static Scheduling getScheduling() { return scheduling;}

    /** Read in the initial Schedule Weighting Parameters from a file 
     * WeightParams ( x[], y[], beta, vlow, vhi, inclusive ). */
    public static void loadScheduleWeightingParams()  throws ServerEnvException{
	try {
	    scheduling.loadEssential(globalSettings.getSchedulingParametersFile());
	} catch (IllegalArgumentException e) {
	    throw new ServerEnvException("Error loading schedule parameters from file \n["+
					 globalSettings.getSchedulingParametersFile().getPath()+"]\n: "+e);
	}
	try {
	    scheduling.mergeWeights(globalSettings.getWeightingParametersFile());
	} catch (IllegalArgumentException e) {
	    throw new ServerEnvException("Error loading weighting parameters from file \n["+
					 globalSettings.getWeightingParametersFile().getPath()+"]\n: "+e);
	}
    }
    
    // Telescope parameters.
    private static TelescopeParameters telescopeParameters = new TelescopeParameters();
    
    public static TelescopeParameters getTelescopeParameters() {return telescopeParameters;} 
    
    /** read in the initial telescope parameters. */
    public static void loadTelescopeParameters() throws ServerEnvException {
	try {
	    telescopeParameters.configure(globalSettings.getTelescopeParametersFile());
	} catch (IOException iox) {
	    throw new ServerEnvException("Error loading telescope parameters from file \n[ "+
					 globalSettings.getTelescopeParametersFile().getPath()+" ]\n: "+iox);
	} catch (IllegalArgumentException e) {
	    throw new ServerEnvException("Error loading telescope parameters from file \n[ "+
					globalSettings.getTelescopeParametersFile().getPath()+" ]\n: "+e);
	}
    }

    // Client settings.
    private static Properties clientSettings = new Properties();
    
    public static Properties getClientSettings() {return clientSettings;}
    
    /** Read in the initial client settings. */
    public static void loadClientSettings()  throws ServerEnvException {
	try {
	    clientSettings.load(new FileInputStream(globalSettings.getClientSettingsFile()));
	} catch (Exception ex) {
	    throw new ServerEnvException("Error loading client settings  from file \n[ "+
					 globalSettings.getClientSettingsFile().getPath()+" ]\n: "+ex);
	} 
    }
    
    // Authentication.
    private static CryptoAuthenticator authenticator = null;

    public static CryptoAuthenticator getAuthenticator() { return authenticator; }
    
    private static Properties passwordTable = new Properties();
    
    /** Read in the Password table from file.*/
    public static void loadPasswordTable() throws ServerEnvException {
	BufferedInputStream in = null;
	try {
	    in = new BufferedInputStream(new FileInputStream(globalSettings.getPasswordTableFile()));
	} catch (FileNotFoundException e) {
	    throw new ServerEnvException("Error opening password file - could not find file");
	} catch (IOException e) {
	    throw new ServerEnvException("Error opening password file \n[ " + 
					 globalSettings.getPasswordTableFile().getPath()+" ]\n: "+e);	    
	}
	
	try {
	    passwordTable.load(in);   
	} catch( IOException ie) {
	    throw  new ServerEnvException("Error loading password table");
	}
	
	try {
	    in.close(); 
	} catch( IOException ie) {
	    log("Error closing password table file");
	} 	

	authenticator = new CryptoAuthenticator(passwordTable, "OSS_SERVER");

    }
    
    /** Attempt to insert a new password table entry.*/
    public static void insertPasswordTableEntry(String path, String password) throws ServerEnvException{
	if (passwordTable.getProperty(path) != null) {
	    log("Attempt to Insert over existing Password Entry: "+path+" / "+password);
	    throw new ServerEnvException("Illegal Password Insertion");
	}
	log("About to save password for user: "+path+" Pwd: "+password);
	passwordTable.setProperty(path, password);
	savePasswordTableUpdate();
    }


    /** Attempt to modify an existing password table entry.*/
    public static void changePasswordTableEntry(String path, String password) throws ServerEnvException{
	if (passwordTable.getProperty(path) == null) {
	    log("Attempt to modify non-existant password entry: "+path+" / "+password);
	    throw new ServerEnvException("Illegal Password Modification");
	}
	passwordTable.setProperty(path, password);
	savePasswordTableUpdate();
    }


    /** Update the password file with new entries. */
    public static void savePasswordTableUpdate() throws ServerEnvException {
	BufferedOutputStream out = null;
	try {
	    out = new BufferedOutputStream(new FileOutputStream(globalSettings.getPasswordTableFile()));
	} catch (FileNotFoundException fe1) {
	    log("Error opening password file - could not find file");
	    throw new ServerEnvException("Could not find Password Table file");
	} catch (IOException ie1) {
	    log("Error opening password file: " + globalSettings.getPasswordTableFile().getPath());
	    throw new ServerEnvException("Error opening Password Table file");	    
	}			   
	try {
	    passwordTable.store(out, "Password Table");
	} catch( IOException ie) {
	    log("Error saving password table updates");
	    throw  new ServerEnvException("Error saving Password Table");
	}
	try {
	    out.close();
	} catch( IOException ie) {
	    log("Error closing password table file");
	} 
    }

   
    public static final String decrypt(String in) { return in; }// these will be changed to do
   
    public static final String encrypt(String in) { return in; }// something useful later.
     
    // Authorization.
    private static Properties authorizationTable = new Properties();

    public static Properties getAuthorizationTable() { return authorizationTable;}
    
    /** Read in the authorization table.*/
    public static void loadAuthorizationTable() throws ServerEnvException {
	BufferedInputStream in = null;
	try {
	    in = new BufferedInputStream(new FileInputStream(globalSettings.getAuthorizationTableFile()));
	} catch (FileNotFoundException fe1) {
	    throw new ServerEnvException("Error opening authorization file - could not find file");
	} catch (IOException ie1) {
	    throw new ServerEnvException("Error opening authorization file: " + 
					 globalSettings.getAuthorizationTableFile().getPath());	
	}
	
	try {
	    authorizationTable.load(in);	    
	} catch( IOException ie) {
	    throw  new ServerEnvException();
	}
	
	try {
	    in.close(); 
	} catch( IOException ie) {
	    throw new ServerEnvException("Error closing authorization table file");
	} 
    }

    // Transaction Queue .    
    private static TransactionQueue transQueue = null; 

    public static void setTransQueue(TransactionQueue in) {transQueue = in;}
    
    public static TransactionQueue getTransQueue() { return transQueue;}
       
    // Hooks to main server objects.

    // Statistics setup.
    private static ServerStatistics serverStats = null;
    
    public static void setServerStats(ServerStatistics in) { serverStats = in;}
    
    public static ServerStatistics getServerStats() { return serverStats;}


    // Database setup.
    private static Database database = null; 
    
    public static void setDatabase(Database in) { database = in;}

    public static Database getDatabase() { return database;}

    // Logging variables.

    private static final SimpleDateFormat sdf = new SimpleDateFormat("dd:MM:yy : hh.mm.ss");   

    public static void log(String text) {
	logger.log(1, text);
    }
   
    public static void dumpStack(Exception ex) {
	ex.printStackTrace();
    }

} // end class def [ServerEnvironment].













